
#include <BMap>
#include <BScript>
#include "IClassMap.h"

using namespace BWE;

typedef BMap<BValue, BValue>	BValueMap;

ClassMap::ClassMap() : BClass(" map < Tk, Tv > ")
{
	insertMethod("map<Tk, Tv>()", &ClassMap::create);
	insertMethod("map<Tk, Tv>(const map< Tk, Tv> &)", &ClassMap::create_other);
	insertMethod("~map<Tk, Tv>()", &ClassMap::release);

	insertMethod("int size() const;", &ClassMap::size);
	insertMethod("int capacity() const;", &ClassMap::capacity);

	insertMethod("bool empty() const;", &ClassMap::empty);
	insertMethod("bool reset();", &ClassMap::reset);
	insertMethod("bool clear();", &ClassMap::clear);
	insertMethod("bool relax();", &ClassMap::relax);

	insertMethod("bool reserve(int);", &ClassMap::reserve);
	insertMethod("bool check(int) const;", &ClassMap::check);
	insertMethod("bool resort();", &ClassMap::resort);

	insertMethod("bool contain(const Tk&) const;", &ClassMap::contain);
	insertMethod("int index(const Tk&) const;", &ClassMap::index);

	insertMethod("Tk& key(int) const;", &ClassMap::key);
	insertMethod("Tv& value(int) const;", &ClassMap::value);

	insertMethod("Tv& first();", &ClassMap::first);
	insertMethod("const Tv& first() const;", &ClassMap::first_const);

	insertMethod("Tv& middle();", &ClassMap::middle);
	insertMethod("const Tv& middle() const;", &ClassMap::middle_const);

	insertMethod("Tv& last();", &ClassMap::last);
	insertMethod("const Tv& last() const;", &ClassMap::last_const);

	insertMethod("Tv& min();", &ClassMap::min);
	insertMethod("const Tv& min() const;", &ClassMap::min_const);

	insertMethod("Tv& max();", &ClassMap::max);
	insertMethod("const Tv& max() const;", &ClassMap::max_const);

	insertMethod("Tv& at(const Tk&);", &ClassMap::at);
	insertMethod("const Tv& at(const Tk&) const;", &ClassMap::at_const);

	insertMethod("Tv& def()", &ClassMap::def);
	insertMethod("const Tv& def() const;", &ClassMap::def_const);

	insertMethod("bool set(const Tk&, const Tv&);", &ClassMap::set);

	insertMethod("bool fill(const Tv& value);", &ClassMap::fill_value);
	insertMethod("bool fill(const Tv& value, int pos, int size);", &ClassMap::fill_value_pos_size);

	insertMethod("int insert(const Tk& key);", &ClassMap::insert_key);
	insertMethod("int insert(const Tk& key, const Tv& value);", &ClassMap::insert_key_value);
	insertMethod("void insert(const map< Tk, Tv> & other);", &ClassMap::insert_other);

	insertMethod("bool remove(const Tk&);", &ClassMap::remove_key);
	insertMethod("int remove(const map<Tk, Tv>&);", &ClassMap::remove_other);
	insertMethod("bool remove(int, int);", &ClassMap::remove_pos_count);

	insertMethod("int find(const Tk&) const;", &ClassMap::find);

	//insertMethod("Tv& ()(const Tk&);", &ClassMap::operator_bracket);
	insertMethod("const Tv& ()(const Tk&) const;", &ClassMap::operator_bracket_const);

	//insertMethod("Tv& [](const Tk&);", &ClassMap::operator_square_bracket);
	insertMethod("const Tv& [](const Tk&) const;", &ClassMap::operator_square_bracket_const);

	insertMethod("const map<Tk,Tv>& = (const map<Tk,Tv>&);", &ClassMap::operator_assign);
	insertMethod("const map<Tk,Tv>& << (const map<Tk,Tv>&);", &ClassMap::operator_append);

	insertMethod("bool == (const map<Tk,Tv>&) const;", &ClassMap::operator_equal_other);
	insertMethod("bool != (const map<Tk,Tv>&) const;", &ClassMap::operator_unequal_other);

	insertMethod("int == (const Tk&);", &ClassMap::operator_equal);

	insertMethod("int < (const Tk&);", &ClassMap::operator_less);
	insertMethod("int <= (const Tk&);", &ClassMap::operator_less_equal);

	insertMethod("int > (const Tk&);", &ClassMap::operator_greater);
	insertMethod("int >= (const Tk&);", &ClassMap::operator_greater_equal);

}

BClass* ClassMap::clone() const
{
	ClassMap* cls = new ClassMap();
	cls->copy(this);
	return cls;
}

void ClassMap::create(int argc, BValue* argv)
{
	BValueMap* valueMap = new BValueMap();
	this->setAsset(valueMap);
}
void ClassMap::create_other(int argc, BValue* argv)
{
	BValueMap* valueMap = new BValueMap();
	if (ClassMap* otherMap = argv[0])
	{
		const BValueMap& other = otherMap->asset();
		*valueMap = other;
	}
	this->setAsset(valueMap);
}
void ClassMap::release(int argc, BValue* argv)
{
	BValueMap* valueMap = new BValueMap();
	valueMap->clear();
}

void ClassMap::size(int argc, BValue* argv)
{
	const BValueMap* valueMap = this->asset();
	argv[0] = valueMap->size();
}
void ClassMap::capacity(int argc, BValue* argv)
{
	const BValueMap& valueMap = this->asset();
	argv[0] = valueMap.capacity();
}

void ClassMap::empty(int argc, BValue* argv)
{
	const BValueMap& valueMap = this->asset();
	argv[0] = valueMap.empty();
}
void ClassMap::reset(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	argv[0] = valueMap.reset();
}
void ClassMap::clear(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	argv[0] = valueMap.clear();
}
void ClassMap::relax(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	argv[0] = valueMap.relax();
}

void ClassMap::reserve(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	int size = argv[1];
	argv[0] = valueMap.reserve(size);
}
void ClassMap::check(int argc, BValue* argv)
{
	const BValueMap& valueMap = this->asset();
	int index = argv[1];
	argv[0] = valueMap.check(index);
}
void ClassMap::resort(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	argv[0] = valueMap.resort();
}

void ClassMap::contain(int argc, BValue* argv)
{
	const BValueMap& valueMap = this->asset();
	const BValue& key = argv[1];
	argv[0] = valueMap.contain(key);
}
void ClassMap::index(int argc, BValue* argv)
{
	const BValueMap& valueMap = this->asset();
	const BValue& key = argv[1];
	argv[0] = valueMap.index(key);
}

void ClassMap::key(int argc, BValue* argv)
{
	const BValueMap& valueMap = this->asset();
	int index = argv[1];
	argv[0] = valueMap.key(index);
}
void ClassMap::value(int argc, BValue* argv)
{
	const BValueMap& valueMap = this->asset();
	int index = argv[1];
	argv[0] = valueMap.value(index);
}

void ClassMap::first(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	argv[0] = valueMap.first();
}
void ClassMap::first_const(int argc, BValue* argv)
{
	const BValueMap& valueMap = this->asset();
	argv[0] = valueMap.first();
}

void ClassMap::middle(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	argv[0] = valueMap.middle();
}
void ClassMap::middle_const(int argc, BValue* argv)
{
	const BValueMap& valueMap = this->asset();
	argv[0] = valueMap.middle();
}

void ClassMap::last(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	argv[0] = valueMap.last();
}
void ClassMap::last_const(int argc, BValue* argv)
{
	const BValueMap& valueMap = this->asset();
	argv[0] = valueMap.last();
}

void ClassMap::min(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	argv[0] = valueMap.min();
}
void ClassMap::min_const(int argc, BValue* argv)
{
	const BValueMap& valueMap = this->asset();
	argv[0] = valueMap.min();
}

void ClassMap::max(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	argv[0] = valueMap.max();
}
void ClassMap::max_const(int argc, BValue* argv)
{
	const BValueMap& valueMap = this->asset();
	argv[0] = valueMap.max();
}

void ClassMap::at(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	const BValue& key = argv[1];
	argv[0] = valueMap.at(key);
}
void ClassMap::at_const(int argc, BValue* argv)
{
	const BValueMap& valueMap = this->asset();
	const BValue& key = argv[1];
	argv[0] = valueMap.at(key);
}

void ClassMap::def(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	argv[0] = valueMap.def();
}
void ClassMap::def_const(int argc, BValue* argv)
{
	const BValueMap& valueMap = this->asset();
	argv[0] = valueMap.def();
}

void ClassMap::set(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	const BValue& key = argv[1];
	const BValue& value = argv[2];
	argv[0] = valueMap.set(key, value);
}

void ClassMap::fill_value(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	const BValue& value = argv[1];
	argv[0] = valueMap.fill(value);
}
void ClassMap::fill_value_pos_size(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	const BValue& value = argv[1];
	int pos = argv[2];
	int size = argv[3];
	argv[0] = valueMap.fill(value, pos, size);
}

void ClassMap::insert_key(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	const BValue& key = argv[1];
	auto it = valueMap.insert(key);
	this->script()->create(this->tempTypes()(1), *it);
	argv[0] = it.index();
}
void ClassMap::insert_key_value(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	const BValue& key = argv[1];
	const BValue& value = argv[2].refer();
	auto it = valueMap.insert(key, value);
	argv[0] = it.index();
}
void ClassMap::insert_other(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	if (const ClassMap* otherMap = argv[1])
	{
		const BValueMap& other = otherMap->asset();
		valueMap.insert(other);
	}
}

void ClassMap::remove_key(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	const BValue& key = argv[1];
	argv[0] = valueMap.remove(key);
}
void ClassMap::remove_other(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	if (const ClassMap* otherMap = argv[1])
	{
		const BValueMap& other = otherMap->asset();
		int count = 0;
		for (int i = 0; i < other.size(); i++)
		{
			if (valueMap.remove(other.key(i)))
				count++;
		}
		argv[0] = count;
	}
}
void ClassMap::remove_pos_count(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	int pos = argv[1];
	int count = argv[2];
	argv[0] = valueMap.remove(pos, count);
}

void ClassMap::find(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	const BValue& key = argv[1];
	auto it = valueMap.find(key);
	argv[0] = it.index();
}

void ClassMap::operator_bracket(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	const BValue& key = argv[1];
	argv[0] = valueMap(key);
}
void ClassMap::operator_bracket_const(int argc, BValue* argv)
{
	const BValueMap& valueMap = this->asset();
	const BValue& key = argv[1];
	argv[0] = valueMap(key);
}

void ClassMap::operator_square_bracket(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	const BValue& key = argv[1];
	argv[0] = valueMap[key];
}
void ClassMap::operator_square_bracket_const(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	const BValue& key = argv[1];
	argv[0] = valueMap[key];
}

void ClassMap::operator_assign(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	if (const ClassMap* otherMap = argv[1])
	{
		const BValueMap& other = otherMap->asset();
		valueMap = other;
	}
}
void ClassMap::operator_append(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	if (const ClassMap* otherMap = argv[1])
	{
		const BValueMap& other = otherMap->asset();
		valueMap << other;
	}
}

void ClassMap::operator_equal_other(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	if (const ClassMap* otherMap = argv[1])
	{
		const BValueMap& other = otherMap->asset();
		argv[0] = valueMap == other;
	}
	else
	{
		argv[0] = false;
	}
}
void ClassMap::operator_unequal_other(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	if (const ClassMap* otherMap = argv[1])
	{
		const BValueMap& other = otherMap->asset();
		argv[0] = valueMap != other;
	}
	else
	{
		argv[0] = false;
	}
}

void ClassMap::operator_equal(int argc, BValue* argv)
{
	BValueMap& valueMap = this->asset();
	const BValue& key = argv[1];
	auto it = valueMap == key;
	argv[0] = it.index();
}

void ClassMap::operator_less(int argc, BValue* argv)
{
	const BValueMap& valueMap = this->asset();
	const BValue& key = argv[1];
	auto it = valueMap < key;
	argv[0] = it.index();
}
void ClassMap::operator_less_equal(int argc, BValue* argv)
{
	const BValueMap& valueMap = this->asset();
	const BValue& key = argv[1];
	auto it = valueMap <= key;
	argv[0] = it.index();
}

void ClassMap::operator_greater(int argc, BValue* argv)
{
	const BValueMap& valueMap = this->asset();
	const BValue& key = argv[1];
	auto it = valueMap > key;
	argv[0] = it.index();
}
void ClassMap::operator_greater_equal(int argc, BValue* argv)
{
	const BValueMap& valueMap = this->asset();
	const BValue& key = argv[1];
	auto it = valueMap >= key;
	argv[0] = it.index();
}
